/* Copyright (c) 2008, dZettaApart.
   Licensed under the BSD License.
   See COPYING for details. */

#include <cstdlib>
#include <map>

#include <boost/bind.hpp>
#include <boost/asio.hpp>
#include <boost/thread.hpp>
#include <boost/regex.hpp>

#include "memcacheasio_request.h"

using namespace memcacheasio;
using namespace std;
using namespace boost;
using namespace boost::asio;

namespace memcacheasio
{
	/** ***************************************************************************
	 *  Request::Request
	 *
	 *****************************************************************************/
	Request::Request ( int command,
	                   const std::string key,
	                   const std::string value )
	{
		_command = command;
		_key = key;
		_value = value;
		_status = false;
	}

	/** ***************************************************************************
	 *  Request::~Request
	 *
	 *****************************************************************************/
	Request::~Request()
	{
	}

	/** ***************************************************************************
	 *  Request::command
	 *
	 *****************************************************************************/
	int Request::command() { return _command; };

	/** ***************************************************************************
	 *  Request::key
	 *
	 *****************************************************************************/
	std::string Request::key() { return _key; };

	/** ***************************************************************************
	 *  Request::response
	 *
	 *****************************************************************************/
	std::string Request::response()
	{
		if ( _multy_value.begin() == _multy_value.end() )
			return "";
		return _multy_value.begin()->second;
	};

	/** ***************************************************************************
	 *  Request::multyResponse
	 *
	 *****************************************************************************/
	std::map< std::string, std::string > Request::multyResponse() { return _multy_value; };

	/** ***************************************************************************
	 *  Request::responseStatus
	 *
	 *****************************************************************************/
	bool Request::responseStatus() { return _status; };

	/** ***************************************************************************
	 *  Request::request
	 *
	 *****************************************************************************/
	std::string Request::request()
	{
		std::string request = "";
		switch ( _command )
		{
			case COMMAND_GET :
			{
				request = "get " + _key + "\r\n";
				break;
			}
			case COMMAND_SET:
			{
				request = "set " + _key + " 0 0 " + boost::lexical_cast<std::string> ( _value.size() ) +"\r\n" + _value +"\r\n";
				break;
			}
			case COMMAND_DELETE:
			{
				request = "delete " + _key + "\r\n";
				break;
			}
			case COMMAND_INCR:
			{
				request = "incr " + _key + " " + _value + "\r\n";

				break;
			}
			case COMMAND_DECR:
			{
				request = "decr " + _key + " " + _value + "\r\n";
				break;
			}
			case COMMAND_ADD:
			{
				request = "add " + _key + " 0 0 " + boost::lexical_cast<std::string> ( _value.size() ) +"\r\n" + _value +"\r\n";
				break;
			}
		}
		return request;

	}

	/** ***************************************************************************
	 *  Request::setResponse
	 *
	 *****************************************************************************/
	void Request::setResponse ( const std::string& response )
	{
		// Контейнер для значений
		std::vector<std::string> values;
		switch ( _command )
		{
			case COMMAND_GET :
			{
				if ( response == "END\r\n" )
				{
					_value = "";
					_status = true;
					break;
				}
				boost::smatch what;
				std::string::const_iterator start = response.begin();
				std::string::const_iterator end = response.end();
				while ( regex_search ( start, end, what, boost::regex ( "^VALUE\\s([^\\s]+)\\s(\\d+)\\s(\\d+)\r\n([^\r]+)" ) ) )
				{
					std::string key = std::string ( what[1].first, what[1].second );
					std::string data = std::string ( what[4].first, what[4].second );
					int archive = data.find ( "::archive" );
					if ( archive  > 0 )
						&data.erase ( archive );
					_multy_value.insert ( pair<std::string, std::string > ( key, data ) );
					// update search position:
					start = what[4].second;
				}
				_status = true;
				break;
			}
			case COMMAND_SET:
			{
				if ( response == "STORED\r\n" ) _status = true;
				_value.assign ( response );
				_multy_value.insert ( pair<std::string, std::string > ( _key, _value ) );
				break;
			}
			case COMMAND_DELETE:
			{
				if ( response == "DELETED\r\n" ) _status = true;
				_value.assign ( response );
				_multy_value.insert ( pair<std::string, std::string > ( _key, _value ) );
				break;
			}
			case COMMAND_INCR:
			{
				if ( response != "NOT_FOUND\r\n" && response != "NOT_CONNECTED\r\n" ) _status = true;
				_value.assign ( response, 0, response.length()-2 );
				_multy_value.insert ( pair<std::string, std::string > ( _key, _value ) );
				break;
			}
			case COMMAND_DECR:
			{
				if ( response != "NOT_FOUND\r\n" && response != "NOT_CONNECTED\r\n" ) _status = true;
				_value.assign ( response );
				_multy_value.insert ( pair<std::string, std::string > ( _key, _value ) );
				break;
			}
			case COMMAND_ADD:
			{
				if ( response == "STORED\r\n" || response == "NOT_STORED\r\n" ) _status = true;
				_value.assign ( response );
				_multy_value.insert ( pair<std::string, std::string > ( _key, _value ) );
				break;
			}
		}
	}
} //namespace memcacheasio
